package com.zkthink.ceres.finance.service.impl;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.zkthink.base.R;
import com.zkthink.base.request.PageParams;
import com.zkthink.base.service.SuperServiceImpl;
import com.zkthink.ceres.finance.dao.CashOutDetailMapper;
import com.zkthink.ceres.finance.dao.JournalDetailMapper;
import com.zkthink.ceres.finance.dto.*;
import com.zkthink.ceres.finance.entity.JournalDetail;
import com.zkthink.ceres.finance.enums.PaymentTypeEnum;
import com.zkthink.ceres.finance.enums.TimeGroupEnum;
import com.zkthink.ceres.finance.service.JournalDetailService;

import com.zkthink.context.BaseContextHandler;
import com.zkthink.database.properties.DatabaseProperties;
import com.zkthink.dozer.DozerUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * <p>
 * 业务实现类
 * 流水明细表
 * </p>
 *
 * @author vivi.huang
 * @date 2020-05-25
 */
@Slf4j
@Service
@AllArgsConstructor
public class JournalDetailServiceImpl extends SuperServiceImpl<JournalDetailMapper, JournalDetail> implements JournalDetailService {

    private JournalDetailMapper journalDetailMapper;
    private CashOutDetailMapper cashOutDetailMapper;
    private DozerUtils dozerUtils;
    private DatabaseProperties databaseProperties;

    @Override
    public R<IPage<JournalSummaryDTO>> findJournalSummaryPage(PageParams<JournalSummaryPageDTO> params) {
        // 处理参数
        IPage<JournalSummaryDTO> page = params.getPage();
        queryJournalSummary(params, page);
        return R.success(page);
    }

    private void queryJournalSummary(PageParams<JournalSummaryPageDTO> params, IPage<JournalSummaryDTO>  page) {

        JournalSummaryPageDTO pageDTO = params.getModel();

        String timeFormat = getTimeFormat(pageDTO.getGroupDateType());

        List<JournalSummaryDTO> journalSummaryDTOList = journalDetailMapper.findJournalSummaryPage(
                timeFormat, pageDTO.getDate(), (params.getCurrent() - 1) * params.getSize(), params.getSize());

        page.setRecords(journalSummaryDTOList);

        int count = journalDetailMapper.getTotalOfJournalSummaryPage(timeFormat, pageDTO.getDate());

        page.setTotal(count);
    }

    private String getTimeFormat(Integer groupDateType) {
        String timeFormat;
        if (TimeGroupEnum.BY_DAY.getCode() == groupDateType) {
            timeFormat = "%Y-%m-%d";
        } else {
            timeFormat = "%Y-%m";
        }
        return timeFormat;
    }

    @Override
    public R<IPage<JournalDetail>> findJournalDetailPage(PageParams<JournalDetailPageDTO> params) {
        IPage<JournalDetail> page = params.getPage();
        queryJournalDetail(params, page);
        return R.success(page);
    }

    @Override
    public R<Boolean> saveJournalDetail(JournalDetailSaveDTO journalDetailSaveDTO) {
        synchronized (this) {
            JournalDetail journalDetail = dozerUtils.map(journalDetailSaveDTO, JournalDetail.class);
            journalDetail.setBalance(countBalance(journalDetailSaveDTO));
            journalDetail.setTenantCode(journalDetailSaveDTO.getTenantCode());

            DatabaseProperties.Id idPro = databaseProperties.getId();
            Long bizId = Long.valueOf(IdUtil.getSnowflake(idPro.getWorkerId(), idPro.getDataCenterId()).nextIdStr());
            journalDetail.setId(bizId);

            journalDetail.setEntryTime(LocalDateTime.now());
            journalDetail.setCreateTime(LocalDateTime.now());
            journalDetail.setCreateUser(BaseContextHandler.getUserId());
            journalDetail.setUpdateTime(LocalDateTime.now());
            journalDetail.setUpdateUser(BaseContextHandler.getUserId());

            return R.success(this.journalDetailMapper.insertJournalDetail(journalDetail));
        }
    }

    private Long countBalance(JournalDetailSaveDTO journalDetailSaveDTO) {
        Long lastBalance = this.journalDetailMapper.getLastBalanceOfJournalDetail(journalDetailSaveDTO.getTenantCode());
        if (journalDetailSaveDTO.getPaymentType().intValue() == PaymentTypeEnum.PAY_OUT.getCode()) {
            return Optional.ofNullable(lastBalance).map(l -> l - journalDetailSaveDTO.getAmount()).orElse(0L);
        }
        return Optional.ofNullable(lastBalance).map(l -> l + journalDetailSaveDTO.getAmount()).orElse(journalDetailSaveDTO.getAmount()) ;
    }

    @Override
    public R<AccountSummaryDTO> getAccountSummary() {
        AccountSummaryDTO accountSummaryDTO = this.journalDetailMapper.getAccountSummary(BaseContextHandler.getTenant());

        if (accountSummaryDTO == null) {
            return R.success(new AccountSummaryDTO());
        }


        Long cashOutApplyMoney = this.cashOutDetailMapper.getCashOutApplyMoney();
        accountSummaryDTO.setCashOutApplyMoney(Optional.ofNullable(cashOutApplyMoney).orElse(0L));
        return R.success(accountSummaryDTO);
    }

    private void queryJournalDetail(PageParams<JournalDetailPageDTO> params, IPage<JournalDetail> page) {
        JournalDetailPageDTO pageDTO = params.getModel();

        String timeFormat = getTimeFormat(pageDTO.getGroupDateType());

        Integer total = this.journalDetailMapper.getTotalOfJournalDetailPage(timeFormat, pageDTO.getDate(),
                pageDTO.getPaymentType(), pageDTO.getJournalType());

        if (total > 0) {
            List<JournalDetail> journalDetails = this.journalDetailMapper.findJournalDetailPage(timeFormat, pageDTO.getDate(),
                    pageDTO.getPaymentType(), pageDTO.getJournalType(), (page.getCurrent() - 1), page.getSize());

            page.setRecords(journalDetails);
            page.setTotal(total);
        }

    }

    @Override
    public R<IPage<PlatformFinanceDTO>> getPlatformFinanceDTOPage(PageParams<PlatformFinanceDTO> params) {
        IPage<PlatformFinanceDTO> page = params.getPage();
        queryPlatformFinance(params, page);
        return R.success(page);
    }


    private void queryPlatformFinance(PageParams<PlatformFinanceDTO> params, IPage<PlatformFinanceDTO> page) {
        PlatformFinanceDTO pageDTO = params.getModel();

        int count = journalDetailMapper.getTotalOfPlatformFinancePage(pageDTO.getTenantName(), pageDTO.getTenantCode());

        if (count > 0) {
            List<PlatformFinanceDTO> platformFinanceDTOList = journalDetailMapper.findPlatformFinancePage(pageDTO.getTenantName(), pageDTO.getTenantCode(),
                    (params.getCurrent() - 1) * params.getSize(), params.getSize());

            page.setRecords(platformFinanceDTOList);
        }

        page.setTotal(count);
    }

    @Override
    public R<PlatformFinanceDTO> getPlatformFinanceSummary() {
        return R.success(journalDetailMapper.getPlatformFinanceSummary());
    }


}
